﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using TradeHelp.Utilities;

namespace TradeHelp.MaterializedObjectViews
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ViewMessageBurst<T> : ReadOnlyCollection<ViewMessage<T>>
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="list"></param>
        /// <param name="viewVersion"></param>
        public ViewMessageBurst(IList<ViewMessage<T>> list, int viewVersion) 
            : this(list, viewVersion, false)
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="list"></param>
        /// <param name="viewVersion"></param>
        /// <param name="initialBurst"></param>
        public ViewMessageBurst(IList<ViewMessage<T>> list, int viewVersion, bool initialBurst)
            : base(list)
        {
            Invariant.CheckIsNull(list, "list");
            InitialBurst = initialBurst;
            ViewVersion = viewVersion;
        }

        /// <summary>
        /// 
        /// </summary>
        public int ViewVersion { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        public bool InitialBurst { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="selector"></param>
        /// <returns></returns>
        public ViewMessageBurst<TResult> Select<TResult>(Func<T, TResult> selector)
        {
            var data = Enumerable.Select(this, msg => msg.Convert(selector)).ToList();
            return new ViewMessageBurst<TResult>(data, ViewVersion, InitialBurst);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public ViewMessageBurst<T> Where(Func<T, bool> predicate)
        {
            var data = new List<ViewMessage<T>>();
            foreach (var msg in this)
            {
                if (msg.Action == ViewAction.Add)
                {
                    if (predicate(msg.Data))
                    {
                        data.Add(msg);
                    }
                }
                else if (msg.Action == ViewAction.Remove)
                {
                    if (predicate(msg.Data))
                    {
                        data.Add(msg);
                    }
                }
                else if (msg.Action == ViewAction.Update)
                {
                    bool oldPred = predicate(msg.PrevData);
                    bool newPred = predicate(msg.Data);
                    if (oldPred && newPred)
                    {
                        data.Add(msg);
                    }
                    else if (oldPred)
                    {
                        data.Add(ViewMessage<T>.CreateRemove(msg.PrevData));
                    }
                    else if (newPred)
                    {
                        data.Add(ViewMessage<T>.CreateAdd(msg.Data));
                    }
                }
                else
                {
                    throw new ArgumentOutOfRangeException();
                }
            }
            return new ViewMessageBurst<T>(data, ViewVersion, InitialBurst);
        }
    }
}